﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace HZY.EFCore
{
    using HZY.EFCore.Interface;
    using Microsoft.EntityFrameworkCore;
    using Z.EntityFramework.Plus;

    public abstract class HZYRepositoryBase<T, TDbContext> : IRepository<T>
        where T : class, new()
        where TDbContext : DbContext
    {
        public HZYUnitOfWorkBase<TDbContext> UnitOfWork { get; set; }

        protected HZYRepositoryBase(TDbContext _Context)
        {
            this.Context = _Context;
            this.UnitOfWork = new HZYUnitOfWorkBase<TDbContext>(_Context);
        }

        public virtual TDbContext Context { get; set; }

        public virtual DbSet<T> Set => this.UnitOfWork.Set<T>();

        public virtual IQueryable<T> Query() => this.Set.AsNoTracking().AsQueryable();

        public virtual IQueryable<T> Query(Expression<Func<T, bool>> Where) => this.Query().Where(Where);

        #region 异步方法

        public virtual async Task<T> InsertAsync(T model)
        {
            await this.Set.AddAsync(model);
            await this.UnitOfWork.SaveAsync();
            return model;
        }

        public virtual async Task<int> UpdateAsync(T model)
        {
            this.Set.Update(model);
            return await this.UnitOfWork.SaveAsync();
        }

        public virtual Task<int> UpdateByIdAsync(T model)
        {
            var keyProperty = Utility.GetKeyProperty(model.GetType());
            var expWhere = Utility.ToWhere<T>(keyProperty.Name, keyProperty.GetValue(model));
            var expMemberInit = Utility.ToMemberInitByModel(model);

            return this.UpdateAsync(expMemberInit, expWhere);
        }

        public virtual Task<int> UpdateAsync(Expression<Func<T, T>> model, Expression<Func<T, bool>> expWhere) => this.Set.Where(expWhere).UpdateFromQueryAsync(model);

        public virtual Task<int> DeleteAsync(T model)
        {
            this.Set.Remove(model);
            return this.UnitOfWork.SaveAsync();
        }

        public virtual Task<int> DeleteRangeAsync(IEnumerable<T> models)
        {
            this.Set.RemoveRange(models);
            return this.UnitOfWork.SaveAsync();
        }

        public virtual async Task<T> FindByIdAsync(object Key) => await this.Set.FindAsync(Key);

        public virtual Task<T> FindAsync(Expression<Func<T, bool>> Where) => this.Query().FirstOrDefaultAsync(Where);

        public virtual Task<List<T>> FindListAsync(Expression<Func<T, bool>> Where) => this.Query().Where(Where).ToListAsync();

        public virtual Task<List<T>> FindAllAsync() => this.Query().ToListAsync();

        public virtual Task<int> CountAsync() => this.Query().CountAsync();

        #endregion

        #region 同步方法

        public virtual T Insert(T model)
        {
            this.Set.Add(model);
            this.UnitOfWork.Save();
            return model;
        }

        public virtual int Update(T model)
        {
            this.Set.Update(model);
            return this.UnitOfWork.Save();
        }

        public virtual int UpdateById(T model)
        {
            var keyProperty = Utility.GetKeyProperty(model.GetType());
            var expWhere = Utility.ToWhere<T>(keyProperty.Name, keyProperty.GetValue(model));
            var expMemberInit = Utility.ToMemberInitByModel(model);

            return this.Update(expMemberInit, expWhere);
        }

        public virtual int Update(Expression<Func<T, T>> model, Expression<Func<T, bool>> expWhere) => this.Set.Where(expWhere).UpdateFromQuery(model);

        public virtual int Delete(T model)
        {
            this.Set.Remove(model);
            return this.UnitOfWork.Save();
        }

        public virtual int DeleteRange(IEnumerable<T> models)
        {
            this.Set.RemoveRange(models);
            return this.UnitOfWork.Save();
        }

        public virtual T FindById(object Key) => this.Set.Find(Key);

        public virtual T Find(Expression<Func<T, bool>> Where) => this.Query().FirstOrDefault(Where);

        public virtual List<T> FindList(Expression<Func<T, bool>> Where) => this.Query().Where(Where).ToList();

        public virtual List<T> FindAll() => this.Query().ToList();

        public virtual int Count() => this.Query().Count();

        #endregion



    }
}
